/**
 * Licensed to Jasig under one or more contributor license agreements. See the NOTICE file distributed with this work
 * for additional information regarding copyright ownership. Jasig licenses this file to you under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy
 * of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 */

package com.baijia.commons.session;

import com.baijia.commons.constant.Constant;
import com.baijia.commons.dession.cache.SessionCache;
import com.baijia.commons.dession.session.CachedSession;
import com.baijia.commons.dession.session.SessionManager;
import com.baijia.commons.util.PPCommonUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * @title SingleSignOutHandler
 * @desc 处理具体登出逻辑
 * @author caoliang
 * @date 2015年12月1日
 * @version 1.0
 */
public final class SingleSignOutHandler {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    private String artifactParameterName = Constant.ARTIFACTPARAMETERNAME;

    private String logoutParameterName = Constant.LOGOUTPARAMETERNAME;

    private SessionCache sessionCache;

    private SessionManager sessionManager;

    public void setArtifactParameterName(final String name) {
        this.artifactParameterName = name;
    }

    public void setLogoutParameterName(final String name) {
        this.logoutParameterName = name;
    }

    public void init(SessionCache sessionCache, SessionManager sessionManager) {
        PPCommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null.");
        PPCommonUtils.assertNotNull(this.logoutParameterName, "logoutParameterName cannot be null.");
        this.sessionCache = sessionCache;
        this.sessionManager = sessionManager;
    }

    /**
     * 是否为附带ST的request
     *
     * @param request HTTP reqest.
     * @return 附带ST返回true
     */
    public boolean isTokenRequest(final HttpServletRequest request) {
        return PPCommonUtils.isNotBlank(PPCommonUtils.safeGetParameter(request, this.artifactParameterName));
    }

    /**
     * 是否为登出request.
     *
     * @param request HTTP request.
     * @return 附带登出参数返回true
     */
    public boolean isLogoutRequest(final HttpServletRequest request) {
        return "POST".equals(request.getMethod()) && !isMultipartRequest(request)
            && PPCommonUtils.isNotBlank(PPCommonUtils.safeGetParameter(request, this.logoutParameterName));
    }

    /**
     * 记录ST
     * 
     * @param request HTTP request containing an authentication token.
     */
    public void recordSession(final HttpServletRequest request) {
        final HttpSession session = request.getSession();

        final String token = PPCommonUtils.safeGetParameter(request, this.artifactParameterName);
        if (logger.isDebugEnabled()) {
            logger.debug("Recording session for token " + token);
        }
        // 原来这里需要把本地session和st的关系做重新绑定，删除老的，绑新的。现在打一行日志表示ST落在哪台机器
        if (logger.isDebugEnabled()) {
            logger.debug("ST info is :" + token + "|session:" + session.getId());
        }
    }

    /**
     * 登出时调用，清理session和<ST,Session>关系
     *
     * @param request HTTP request containing a CAS logout message.
     */
    public void destroySession(final HttpServletRequest request, final HttpServletResponse response) {
        final String logoutMessage = PPCommonUtils.safeGetParameter(request, this.logoutParameterName);
        logger.debug("Logout request, parameterName {}, logoutMessage {}", this.logoutParameterName, logoutMessage);
        sessionManager.invalidateSession((CachedSession) sessionCache.get(logoutMessage));
        sessionCache.delete(logoutMessage);
        try {
            request.getSession().invalidate();
        } catch (Exception e) {
            logger.warn("Error while invalidate session", e);
        }
    }

    private boolean isMultipartRequest(final HttpServletRequest request) {
        return request.getContentType() != null && request.getContentType().toLowerCase().startsWith("multipart");
    }
}
